\lstset{language=C, keywordstyle=\color{violet}\bfseries, commentstyle=\color{red}\textit,stringstyle=\color{black}\ttfamily}
\begin{lstlisting}[breaklines=true, breakatwhitespace=true]
#include <stdio.h>
#include <stdint.h>
#include <spu_mfcio.h>
#include <malloc.h>
#include <unistd.h>
#include <simdmath.h>
#include <simdmath/fmaf4.h>
#include <spu_intrinsics.h>
#include "gero_spu.h"

/* Constants */
#define MAX_TRANSFER_SIZE 16384

/* Data Structures */
typedef struct {
  uint32 length __attribute__((aligned(16)));
  uint64 data __attribute__((aligned(16)));
} conversion_structure;

typedef struct {
  uint32 size __attribute__((aligned(16)));
  uint64 effective_address_vec1 __attribute__((aligned(16)));
  uint64 effective_address_vec2 __attribute__((aligned(16)));
  uint64 effective_address_vec3 __attribute__((aligned(16)));
  uint64 effective_address_res __attribute__((aligned(16)));
  volatile float* vec1 __attribute__((aligned(16)));
  volatile float* vec2 __attribute__((aligned(16)));
  volatile float* vec3 __attribute__((aligned(16)));
  volatile vector float res __attribute__ ((aligned(16)));
} buffer;

/* Global Variables */
volatile buffer buffers[2] __attribute__ ((aligned(128)));
CB_4V cb __attribute__((aligned(128))); 

/* Utility Functions */
inline uint32 MIN(uint32 a, uint32 b) {
  return a < b ? a : b;
}

inline void wait_for_completion(uint32 mask) {
  mfc_write_tag_mask(mask);
  spu_mfcstat(MFC_TAG_UPDATE_ALL);
}


inline void load_vectors_info(uint64 argp, uint64 *current_vec1_pointer, uint64 *current_vec2_pointer, uint64 *current_vec3_pointer, uint64 *current_res_pointer, uint32 *remaining_data)

{
  mfc_getb(&cb, argp, sizeof(cb), 0, 0, 0);
  wait_for_completion(1<<0);
  *remaining_data = cb.size;
  buffers[0].vec1 = (float* )memalign(16,cb.size/2); 
  buffers[0].vec2 = (float* ) memalign(16,cb.size/2);
  buffers[0].vec3 = (float* ) memalign(16,cb.size/2);
  buffers[1].vec1 = (float* ) memalign(16,cb.size/2);
  buffers[1].vec2 = (float* ) memalign(16,cb.size/2);
  buffers[1].vec3 = (float* ) memalign(16,cb.size/2); 

  *current_vec1_pointer = cb.vec1_addr;
  *current_vec2_pointer = cb.vec2_addr;
  *current_vec3_pointer = cb.vec3_addr;
  *current_res_pointer = cb.res_addr;
  buffers[0].size = cb.size/2;
  buffers[1].size = cb.size/2;
}

/* Processing Functions */
inline void initiate_transfer(uint32 buf_idx, uint64 *current_vec1_pointer, uint64 *current_vec2_pointer, uint64 *current_vec3_pointer, uint64 *current_res_pointer, uint32 *remaining_data) 
{
  /* Setup buffer information */
  buffers[buf_idx].effective_address_vec1 = *current_vec1_pointer;
  buffers[buf_idx].effective_address_vec2 = *current_vec2_pointer;
  buffers[buf_idx].effective_address_vec3 = *current_vec3_pointer;
  printf("SPE  adresse vec2: %lld\n", (uint64)buffers[buf_idx].effective_address_vec2); fflush(stdout);
  printf("SPE  adresse vec3: %lld\n", (uint64)buffers[buf_idx].effective_address_vec3); fflush(stdout);*/
  mfc_getf(buffers[buf_idx].vec1, (buffers[buf_idx].effective_address_vec1), 4*sizeof(float), buf_idx, 0, 0);
  mfc_getf(buffers[buf_idx].vec2, (buffers[buf_idx].effective_address_vec2), 4*sizeof(float), buf_idx, 0, 0);
  mfc_getf(buffers[buf_idx].vec3, (buffers[buf_idx].effective_address_vec3), 4*sizeof(float), buf_idx, 0, 0);
  /* Move the data pointers */
  *remaining_data -= 4*sizeof(float);	
  buffers[buf_idx].size -= 4*sizeof(float);
  *current_vec1_pointer += 4*sizeof(float);
  *current_vec2_pointer += 4*sizeof(float);
  *current_vec3_pointer += 4*sizeof(float);
}

inline void process_and_put_back(uint32 buf_idx, uint64 *current_res_pointer ) 
{
  wait_for_completion(1<<buf_idx);
  volatile vector float res __attribute__ ((aligned(16)));
  /* Perform calcul */
  res = spu_madd(*((vector float*)(buffers[buf_idx].vec1)),
	         *((vector float*)(buffers[buf_idx].vec2)),
	         *((vector float*)(buffers[buf_idx].vec3)));
   
  /* Initiate the DMA transfer back using the buffer index as the DMA tag */
  buffers[buf_idx].effective_address_res = *current_res_pointer;
  mfc_putb(&res, buffers[buf_idx].effective_address_res, sizeof(float)*4, buf_idx, 0, 0);
  *current_res_pointer += 4*sizeof(float); 
}

/* Main Code */
int main(uint64 spe_id, uint64 argp) 
{
  uint32 remaining_data;	
  uint64 current_vec1_pointer;
  uint64 current_vec2_pointer;
  uint64 current_vec3_pointer;
  uint64 current_res_pointer;

  load_vectors_info(argp, &current_vec1_pointer, &current_vec2_pointer, &current_vec3_pointer, &current_res_pointer, &remaining_data);

  /* Start filling buffers to prepare for loop (loop assumes both buffers have
   * data coming in) */
  initiate_transfer(0, &current_vec1_pointer, &current_vec2_pointer, &current_vec3_pointer, &current_res_pointer, &remaining_data);
  initiate_transfer(1, &current_vec1_pointer, &current_vec2_pointer, &current_vec3_pointer, &current_res_pointer, &remaining_data);

  int i = 0;
  if  (cb.size>8)
    {
      for (i=0; i<(cb.size/8); i++)
	{ 
	  /* Process buffer 0 */
	  process_and_put_back(0, &current_res_pointer);
	  initiate_transfer(0, &current_vec1_pointer, &current_vec2_pointer, &current_vec3_pointer, &current_res_pointer, &remaining_data);

	  /* Process buffer 1 */
	  process_and_put_back(1, &current_res_pointer);
	  initiate_transfer(1, &current_vec1_pointer, &current_vec2_pointer, &current_vec3_pointer, &current_res_pointer, &remaining_data);
	}
    }
  else
    {
      /* Process buffer 0 */
      process_and_put_back(0, &current_res_pointer);
      initiate_transfer(0, &current_vec1_pointer, &current_vec2_pointer, &current_vec3_pointer, &current_res_pointer, &remaining_data);
    }
  wait_for_completion(1<<0|1<<1);
  free(buffers[0].vec1);
  free(buffers[0].vec2);
  free(buffers[0].vec3);
  free(buffers[1].vec1);
  free(buffers[1].vec2);
  free(buffers[1].vec3);  
  return 0;
}
\end{lstlisting}
